#ifndef _Z_CENTRAL_MULTICONN_CLIENT_H__
#define _Z_CENTRAL_MULTICONN_CLIENT_H__

#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/sys/slist.h>
#include <zephyr/bluetooth/uuid.h>

#ifdef __cplusplus
extern "C" {
#endif

// --- Configuration Check ---
#if defined(CONFIG_MULTICONN_CLIENT_AUTO_ENABLE_CCC) && !defined(CONFIG_MULTICONN_CLIENT_DISCOVER_DESCRIPTORS_ENABLE)
#error "MULTICONN_CLIENT_AUTO_ENABLE_CCC requires MULTICONN_CLIENT_DISCOVER_DESCRIPTORS_ENABLE"
#endif



/** @brief Stores discovered GATT descriptor information. */
typedef struct {
    sys_snode_t node;        /**< Linked list node. */
    struct bt_uuid_128 uuid;   /**< Descriptor UUID. */
    uint16_t handle;       /**< Descriptor attribute handle. */
} multiconn_descriptor_t;

/** @brief Stores discovered GATT characteristic information. */
typedef struct {
    sys_snode_t node;                 /**< Linked list node. */
    struct bt_uuid_128 uuid;            /**< Characteristic UUID. */
    uint16_t decl_handle;           /**< Characteristic declaration handle. */
    uint16_t value_handle;          /**< Characteristic value handle. */
    uint8_t properties;             /**< Characteristic properties (BT_GATT_CHRC_*). */
    struct bt_gatt_subscribe_params sub_params; /**< Pre-filled subscribe parameters (app must manage state). */
#ifdef CONFIG_MULTICONN_CLIENT_DISCOVER_DESCRIPTORS_ENABLE
    sys_slist_t descriptors;        /**< List of discovered descriptors (multiconn_descriptor_t). */
    uint8_t desc_count;             /**< Number of descriptors found. */
    uint16_t ccc_handle;            /**< Handle of the CCCD, if found (0 otherwise). */
#endif
} multiconn_characteristic_t;

/** @brief Stores discovered GATT service information. */
typedef struct {
    sys_snode_t node;                 /**< Linked list node. */
    struct bt_uuid_128 uuid;            /**< Service UUID. */
    uint16_t start_handle;          /**< Service start handle. */
    uint16_t end_handle;            /**< Service end handle. */
    sys_slist_t characteristics;        /**< List of discovered characteristics (multiconn_characteristic_t). */
    uint8_t char_count;             /**< Number of characteristics found. */
} multiconn_service_t;

/** @brief Internal state of the connection initialization process. */
typedef enum {
    MULTICONN_STATE_DISCONNECTED,       /**< Initial state or after disconnection. */
    MULTICONN_STATE_CONNECTED,          /**< Connected, awaiting first action. */
    MULTICONN_STATE_MTU_EXCHANGING,     /**< Performing MTU exchange. */
#ifdef CONFIG_MULTICONN_CLIENT_CONN_PARAM_UPDATE_ENABLE
    MULTICONN_STATE_CONN_PARAM_UPDATING,/**< Requesting connection parameter update. */
#endif
    MULTICONN_STATE_SERVICE_DISCOVERING,/**< Discovering primary services. */
    MULTICONN_STATE_CHAR_DISCOVERING,   /**< Discovering characteristics within services. */
#ifdef CONFIG_MULTICONN_CLIENT_DISCOVER_DESCRIPTORS_ENABLE
    MULTICONN_STATE_DESC_DISCOVERING,   /**< Discovering descriptors for characteristics. */
#endif
#if defined(CONFIG_MULTICONN_CLIENT_AUTO_ENABLE_CCC)
    MULTICONN_STATE_ENABLING_CCC,       /**< Automatically enabling specified CCCDs. */
#endif
    MULTICONN_STATE_READY,              /**< Initialization complete and successful. */
    MULTICONN_STATE_ERROR               /**< An error occurred during initialization. */
} multiconn_state_t;

/**
 * @brief Connection context holding state and discovered data for a single connection.
 *
 * @warning THREAD SAFETY: This structure is accessed by the library internally from
 *          Bluetooth callbacks and the system work queue. If the application needs
 *          to access or modify this structure (especially the discovered data lists)
 *          from a different thread *outside* of the provided `ready` or `disconnected`
 *          callbacks, the application MUST implement its own locking mechanism
 *          (e.g., k_mutex) to protect concurrent access. Reading basic state or handles
 *          after the `ready` callback is generally safe if the connection is stable.
 */
typedef struct multiconn_conn_context {
    struct bt_conn *conn;           /**< Pointer to the Zephyr connection object. */
    bool in_use;                    /**< Flag indicating if this context slot is active. */
    multiconn_state_t state;        /**< Current state of the initialization process. */
    int last_err;                   /**< Stores the last error code (negative errno or positive ATT). */

    /* Internal parameters for ongoing GATT operations */
    struct bt_gatt_exchange_params mtu_params;
    struct bt_gatt_discover_params discover_params;
#if defined(CONFIG_MULTICONN_CLIENT_AUTO_ENABLE_CCC)
    struct bt_gatt_write_params write_params;
#endif

    /* Discovered data storage */
    sys_slist_t services;           /**< List of discovered services (multiconn_service_t). */
    uint8_t service_count;          /**< Number of services discovered. */

    /* Iterators used during discovery/auto-enable phases */
    sys_snode_t *current_service_node;
    sys_snode_t *current_char_node;

    struct k_work work;             /**< Work item for scheduling GATT operations. */

#ifdef CONFIG_MULTICONN_CLIENT_CONN_PARAM_UPDATE_ENABLE
    struct bt_le_conn_param desired_conn_params; /**< Desired connection parameters. */
#endif
} multiconn_conn_context_t;




/** @brief Application callbacks provided during initialization. */
typedef struct {
    /**
     * @brief Called when the initialization sequence for a connection completes.
     *
     * This callback signifies that the library has finished its automated setup
     * (MTU, discovery, optional conn params, optional auto-CCC enable).
     * The application can now start its specific interactions (read/write/subscribe)
     * using the handles found in the context, or handle the initialization failure.
     *
     * @param ctx Pointer to the connection context. Access discovered data here.
     * @param err 0 on successful initialization, negative errno code or positive
     *            ATT error code on failure. If err is non-zero, the connection
     *            might still be active but not fully usable for the intended purpose.
     */
    void (*ready)(struct multiconn_conn_context *ctx, int err);

    /**
     * @brief Called when a connection managed by the library is disconnected.
     *
     * @param ctx Pointer to the context of the disconnected connection. The context
     *            and its discovered data will be cleaned up internally *after*
     *            this callback returns.
     * @param reason The disconnection reason code (BT_HCI_ERR_*).
     */
    void (*disconnected)(struct multiconn_conn_context *ctx, uint8_t reason);

    void (*error)(const bt_addr_le_t *addr, uint8_t err);

} multiconn_client_callbacks_t;




/**
 * @brief Initializes the multi-connection client library.
 *
 * Must be called once during application setup, after Bluetooth subsystem init.
 * Registers necessary Bluetooth callbacks.
 *
 * @param callbacks Pointer to the application-provided callback structure.
 *                  This pointer must remain valid for the lifetime of the library.
 * @return 0 on success, negative errno code on failure.
 */
int multiconn_client_init(const multiconn_client_callbacks_t *callbacks);

/**
 * @brief Sets UUID filters for service and characteristic discovery.
 *
 * If called, the library will only discover and store services/characteristics
 * whose UUIDs are present in the provided lists. If not called, or if lists
 * are NULL/empty, all primary services and their characteristics are discovered
 * (subject to configured limits).
 * Must be called *before* any connections are established.
 * The provided pointer arrays must remain valid for the library's lifetime.
 *
 * @param svc_uuids Array of pointers to service UUIDs to discover. NULL for no filter.
 * @param svc_count Number of service UUIDs in svc_uuids.
 * @param char_uuids Array of pointers to characteristic UUIDs to discover. NULL for no filter.
 * @param char_count Number of characteristic UUIDs in char_uuids.
 * @return 0 on success, -EINVAL if arguments are invalid.
 */
int multiconn_client_set_filter(const struct bt_uuid * const *svc_uuids, size_t svc_count,
                                const struct bt_uuid * const *char_uuids, size_t char_count);

/**
 * @brief Sets the list of characteristic UUIDs for which CCCDs should be automatically enabled.
 *
 * This function is only effective if CONFIG_MULTICONN_CLIENT_AUTO_ENABLE_CCC is enabled.
 * After successful discovery, the library will attempt to write to the CCCD
 * for each UUID in this list, provided the characteristic was found, supports
 * Notify/Indicate, and its CCCD was discovered.
 * Must be called *before* any connections are established.
 * The provided pointer array must remain valid for the library's lifetime.
 *
 * @param uuids Array of pointers to characteristic UUIDs to auto-enable.
 * @param count Number of UUIDs in the array.
 * @return 0 on success, -EINVAL if arguments are invalid, -ENOTSUP if feature disabled.
 */
int multiconn_client_set_auto_enable_list(const struct bt_uuid * const *uuids, size_t count);

/**
 * @brief Retrieves the connection context associated with a Zephyr connection object.
 *
 * @param conn Pointer to the Zephyr connection object.
 * @return Pointer to the corresponding multiconn_conn_context_t, or NULL if
 *         the connection is not managed by the library or not found.
 */
struct multiconn_conn_context *multiconn_client_get_context(struct bt_conn *conn);

/**
 * @brief Helper function to find a characteristic by UUID within a discovered service.
 *
 * @param svc Pointer to the discovered service structure (from context->services list).
 * @param uuid Pointer to the characteristic UUID to find.
 * @return Pointer to the found multiconn_characteristic_t, or NULL if not found.
 */
multiconn_characteristic_t* multiconn_client_find_characteristic(multiconn_service_t *svc,
                                                                 const struct bt_uuid *uuid);

/**
 * @brief Helper function to find a characteristic by UUID and properties within a service.
 *
 * Finds the first characteristic matching the UUID that has *at least one* of the
 * specified properties set.
 *
 * @param svc Pointer to the discovered service structure.
 * @param uuid Pointer to the characteristic UUID to find.
 * @param props_mask Bitmask of desired properties (e.g., BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP).
 * @return Pointer to the found multiconn_characteristic_t, or NULL if not found.
 */
multiconn_characteristic_t* multiconn_client_find_characteristic_with_props(multiconn_service_t *svc,
                                                                            const struct bt_uuid *uuid,
                                                                            uint8_t props_mask);

/**
 * @brief Helper function to find a descriptor by UUID within a discovered characteristic.
 *
 * Requires CONFIG_MULTICONN_CLIENT_DISCOVER_DESCRIPTORS_ENABLE to be enabled.
 *
 * @param chara Pointer to the discovered characteristic structure.
 * @param uuid Pointer to the descriptor UUID to find (e.g., BT_UUID_GATT_CCC).
 * @return Pointer to the found multiconn_descriptor_t, or NULL if not found or feature disabled.
 */
#ifdef CONFIG_MULTICONN_CLIENT_DISCOVER_DESCRIPTORS_ENABLE
multiconn_descriptor_t* multiconn_client_find_descriptor(multiconn_characteristic_t *chara,
                                                         const struct bt_uuid *uuid);
#endif


#ifdef __cplusplus
}
#endif

#endif // _Z_CENTRAL_MULTICONN_CLIENT_H__